#ifndef PIXEL_24_H_INCLUDED
#define PIXEL_24_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "sized_int_types.h"

#pragma pack( push, 1)

struct t_pixel_24
{
	t_uint8 blue;
	t_uint8 green;
	t_uint8 red;

	// Constructors
	t_pixel_24();
	explicit t_pixel_24( t_uint32 arg );
	t_pixel_24( t_uint8 new_red, t_uint8 new_green, t_uint8 new_blue );

	// Operators
	t_pixel_24 & operator&=( t_pixel_24 right );
	t_pixel_24 & operator|=( t_pixel_24 right );
	t_pixel_24 & operator^=( t_pixel_24 right );

	operator t_uint32() const;
};

struct t_pixel_32 : public t_pixel_24
{
	t_uint8 alpha;

	// Constructors
	t_pixel_32();
	t_pixel_32( t_uint8 new_red, t_uint8 new_green, t_uint8 new_blue, t_uint8 new_alpha = 255 );
	t_pixel_32( t_pixel_24 const& arg );
	t_pixel_32( t_uint32 arg );

	// Operators
	t_pixel_32 & operator&=( t_pixel_32 right );
	t_pixel_32 & operator|=( t_pixel_32 right );
	t_pixel_32 & operator^=( t_pixel_32 right );
	
	operator t_uint32() const;
};

#pragma pack(pop)

// -----------------------------------------------------------------------------
// inlines for t_pixel_24
// -----------------------------------------------------------------------------
inline t_pixel_24::t_pixel_24()
{
}

inline t_pixel_24::t_pixel_24( t_uint32 arg )
{
	blue  = static_cast<t_uint8>(arg);
	green = static_cast<t_uint8>(arg >> 8);
	red   = static_cast<t_uint8>(arg >> 16);
}

inline t_pixel_24::t_pixel_24( t_uint8 new_red, t_uint8 new_green, t_uint8 new_blue )
	:	blue( new_blue ), green( new_green ), red( new_red )
{
}

inline t_pixel_24 & t_pixel_24::operator&=( t_pixel_24 right )
{
	blue &= right.blue;
	green &= right.green;
	red &= right.red;
	return *this;
}

inline t_pixel_24 & t_pixel_24::operator|=( t_pixel_24 right )
{
	blue |= right.blue;
	green |= right.green;
	red |= right.red;
	return *this;
}

inline t_pixel_24 & t_pixel_24::operator^=( t_pixel_24 right )
{
	blue ^= right.blue;
	green ^= right.green;
	red ^= right.red;
	return *this;
}

inline t_pixel_24::operator t_uint32() const
{
	return blue | (green << 8) | (red << 16);
}

// -----------------------------------------------------------------------------
// inlines for t_pixel_32
// -----------------------------------------------------------------------------
inline t_pixel_32::t_pixel_32()
{
}

inline t_pixel_32::t_pixel_32( t_uint8 new_red, t_uint8 new_green, t_uint8 new_blue, t_uint8 new_alpha )
	:	t_pixel_24( new_red, new_green, new_blue ), alpha( new_alpha )
{
}

inline t_pixel_32::t_pixel_32( t_pixel_24 const& arg ) : t_pixel_24( arg )
{
	alpha = 255;
}

inline t_pixel_32::t_pixel_32( t_uint32 arg )
{
	*(reinterpret_cast<t_uint32*>(this)) = arg;
}

inline t_pixel_32 & t_pixel_32::operator&=( t_pixel_32 right )
{
	*(reinterpret_cast<t_uint32*>(this)) &= right;
	return *this;
}

inline t_pixel_32 & t_pixel_32::operator|=( t_pixel_32 right )
{
	*(reinterpret_cast<t_uint32*>(this)) |= right;
	return *this;
}

inline t_pixel_32 & t_pixel_32::operator^=( t_pixel_32 right )
{
	*(reinterpret_cast<t_uint32*>(this)) ^= right;
	return *this;
}

inline t_pixel_32::operator t_uint32() const
{
	return *(reinterpret_cast<t_uint32 const*>(this));
}

// -----------------------------------------------------------------------------
// inline comparators
// -----------------------------------------------------------------------------
inline bool operator==( t_pixel_24 const& left, t_pixel_24 const& right )
{
	return left.blue == right.blue && left.green == right.green && left.red == right.red;
}

inline bool operator!=( t_pixel_24 const& left, t_pixel_24 const& right )
{
	return !( left == right );
}

inline bool operator==( t_pixel_32 const& left, t_pixel_32 const& right )
{
	return t_uint32( left ) == t_uint32( right );
}

inline bool operator!=( t_pixel_32 const& left, t_pixel_32 const& right )
{
	return !( left == right );
}

// -----------------------------------------------------------------------------
// Bitwise operators
// -----------------------------------------------------------------------------

inline t_pixel_24 operator&( t_pixel_24 left, t_pixel_24 right )
{
	t_pixel_24 result( left );
	result &= right;
	return result;
}

inline t_pixel_24 operator|( t_pixel_24 left, t_pixel_24 right )
{
	t_pixel_24 result( left );
	result |= right;
	return result;
}

inline t_pixel_24 operator^( t_pixel_24 left, t_pixel_24 right )
{
	t_pixel_24 result( left );
	result ^= right;
	return result;
}

inline t_pixel_32 operator&( t_pixel_32 left, t_pixel_32 right )
{
	t_pixel_32 result( left );
	result &= right;
	return result;
}

inline t_pixel_32 operator|( t_pixel_32 left, t_pixel_32 right )
{
	t_pixel_32 result( left );
	result |= right;
	return result;
}

inline t_pixel_32 operator^( t_pixel_32 left, t_pixel_32 right )
{
	t_pixel_32 result( left );
	result ^= right;
	return result;
}

#endif
